﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using Microsoft.Phone.Shell;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.GamerServices;

namespace PhysicsSimulator
{
    public partial class GamePage : Microsoft.Phone.Controls.PhoneApplicationPage
    {
        const int CM_PIXEL = 80;
        ContentManager contentManager;
        GameTimer timer;
        SpriteBatch spriteBatch;

        CPendulum _pendulum;
        Texture2D _background = null;

        UIElementRenderer elementRenderer;

        CVectorForce _rope;


        private float W;
        private float A;
        private float T;
        private float V_max;
        private float Q_max;
        private float Q_min;
        private float v;
        private float _time;
        private float s;
        private float w_t;
        private float w_d;
        private double alpha;// rad/s
        private double fi;
        private float omega;

        public GamePage()
        {
            InitializeComponent();

            TouchPanel.EnabledGestures = GestureType.Tap | GestureType.FreeDrag | GestureType.DragComplete;

            // Get the content manager from the application
            contentManager = (Application.Current as App).Content;

            // Create a timer for this page
            timer = new GameTimer();
            timer.UpdateInterval = TimeSpan.FromTicks(333333);
            timer.Update += OnUpdate;
            timer.Draw += OnDraw;

            LayoutUpdated += new EventHandler(XNARendering_LayoutUpdated);
        }
        void XNARendering_LayoutUpdated(object sender, EventArgs e)
        {
            // make sure page size is valid
            if (ActualWidth == 0 || ActualHeight == 0)
                return;

            // see if we already have the right sized renderer
            if (elementRenderer != null &&
                elementRenderer.Texture != null &&
                elementRenderer.Texture.Width == (int)ActualWidth &&
                elementRenderer.Texture.Height == (int)ActualHeight)
            {
                return;
            }

            // dispose the current renderer
            if (elementRenderer != null)
                elementRenderer.Dispose();

            // create the renderer
            elementRenderer = new UIElementRenderer(this, (int)ActualWidth, (int)ActualHeight);
        }
        bool fist_load = true;
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // Set the sharing mode of the graphics device to turn on XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

            if (fist_load)
            {
                // Create a new SpriteBatch, which can be used to draw textures.
                spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

                // TODO: use this.content to load your game content here
                _background = contentManager.Load<Texture2D>("Images/pendulum_background");


                _pendulum = new CPendulum(spriteBatch, Vector2.Zero, 0.8f);
                _pendulum.Init(contentManager);

                _rope = new CVectorForce(spriteBatch);
                _rope.Init(contentManager);
                Vector2 rope_position = new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2, 0);
                _rope.Create(rope_position, Vector2.Zero, 2, Color.Gold);
                fist_load = false;
            }

            // Start the timer
            timer.Start();
            
            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // Stop the timer
            timer.Stop();

            // Set the sharing mode of the graphics device to turn off XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

            base.OnNavigatedFrom(e);
        }

        /// <summary>
        /// Allows the page to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// 
        private bool _is_playing = false;
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            HandleInput();
            if (SinglePendulumSettings.check_apply)
            {
                CalculateFist();
                SinglePendulumSettings.check_apply = false;
            }
            else
            {
                if (_is_playing)
                {
                    _time += (float)e.ElapsedTime.TotalMilliseconds / 1000;
                    alpha = (MathHelper.ToRadians(SinglePendulumSettings.Angle) * Math.Cos(omega * _time + fi));
                    s = (float)(A * Math.Cos(omega * _time + fi));
                    v = (float)(2 * SinglePendulumSettings.Gravity * SinglePendulumSettings.RopeLengh * (Math.Cos(alpha) - Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle))));
                    w_t = (float)(2 * SinglePendulumSettings.Gravity * SinglePendulumSettings.RopeLengh * (1 - Math.Cos(alpha)));
                    w_d = 0.5f * SinglePendulumSettings.Weight * v * v;
                    _pendulum.Alpha = alpha;
                    _pendulum.Q = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * (3 * Math.Cos(alpha) - 2 * Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle))));
                    _pendulum.Pt = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * Math.Sin(alpha));

                    float x = (float)(SinglePendulumSettings.RopeLengh * Math.Sin(alpha));
                    float y = (float)(SinglePendulumSettings.RopeLengh * Math.Cos(alpha));

                    _rope.VectorForce = new Vector2(x * CM_PIXEL, y * CM_PIXEL);
                    _pendulum.PendulumPositon = new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2 + x * CM_PIXEL, y * CM_PIXEL);

                    _alpha0_detail.Text = SinglePendulumSettings.Angle.ToString() + "°";
                    _alpha_detail.Text = ((float)(MathHelper.ToDegrees((float)alpha))).ToString() + "°";
                    _l_detail.Text = SinglePendulumSettings.RopeLengh.ToString() + "(m)";
                    _g_detail.Text = SinglePendulumSettings.Gravity.ToString() + "(m/s²)";
                    _m_detail.Text = SinglePendulumSettings.Weight.ToString() + "(kg)";
                    _t_chuki_detail.Text = T.ToString() + "(s)";
                    _a_detail.Text = A.ToString() + "(m)";
                    _s_detail.Text = s.ToString() + "(m)";
                    _vmax_detail.Text = V_max.ToString() + "(m/s)";
                    _v_detail.Text = v.ToString() + "(m/s)";
                    _time_detail.Text = _time.ToString() + "(s)";
                    _p_detail.Text = _pendulum.P.ToString() + "(N)";
                    _pt_detail.Text = _pendulum.Pt.ToString() + "(N)";
                    _qmax_detail.Text = Q_max.ToString() + "(N)";
                    _qmin_detail.Text = Q_min.ToString() + "(N)";
                    _q_detail.Text = _pendulum.Q.ToString() + "(N)";
                    _pn_detail.Text = _pendulum.Pn.ToString() + "(N)";
                    _w_detail.Text = W.ToString() + "(J)";
                    _wt_detail.Text = w_t.ToString() + "(J)";
                    _wd_detail.Text = w_d.ToString() + "(J)";

                }
                if (!SinglePendulumSettings.save_active)
                {
                    GetButton(ButtonTypes.Save).IsEnabled = false;
                    SinglePendulumSettings.save_active = true;
                }
            }
            _pendulum.Update(e);
        }

        enum FistPosition
        {
            Left = 0,
            Right = 1,
            Mid_Left = 2,
            Mid_Right = 3
        }
        private void CalculateFist()
        {
            _is_playing = false;
            _time = 0;

            omega = (float)Math.Sqrt(SinglePendulumSettings.Gravity / SinglePendulumSettings.RopeLengh);
            W = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * SinglePendulumSettings.RopeLengh * (1 - Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle))));
            A = (float)(SinglePendulumSettings.RopeLengh * Math.Sin(MathHelper.ToRadians(SinglePendulumSettings.Angle)));
            T = (float)(2 * MathHelper.Pi * Math.Sqrt(SinglePendulumSettings.RopeLengh / SinglePendulumSettings.Gravity));
            V_max = (float)(2* SinglePendulumSettings.Gravity * SinglePendulumSettings.RopeLengh * (1 - Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle))));
            Q_max = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * (3 - 2 * Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle))));
            Q_min = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle)));

            fi = MathHelper.ToRadians(SinglePendulumSettings.Fi);

            alpha = (MathHelper.ToRadians(SinglePendulumSettings.Angle) * Math.Cos(omega * _time + fi));
            s = (float)(A * Math.Cos(omega * _time + fi));

            float x = s;
            float y = (float)(SinglePendulumSettings.RopeLengh * Math.Cos(alpha));
            _rope.VectorForce = new Vector2(x * CM_PIXEL, y * CM_PIXEL);
            _pendulum.PendulumPositon = new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2 + x * CM_PIXEL, y * CM_PIXEL);

            float cos_alpha = (float)Math.Cos(alpha);
            float cos_alpha_2 = (float)Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle));
            float cos_alpha_3 = cos_alpha - cos_alpha_2;
            v = 2 * SinglePendulumSettings.Gravity * SinglePendulumSettings.RopeLengh * cos_alpha_3;//(Math.Cos(alpha) - Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle))));
            w_t = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * SinglePendulumSettings.RopeLengh * (1 - Math.Cos(alpha)));
            w_d = 0.5f * SinglePendulumSettings.Weight * v * v;
            _pendulum.Alpha = alpha;
            _pendulum.Q = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * (3 * Math.Cos(alpha) - 2 * Math.Cos(MathHelper.ToRadians(SinglePendulumSettings.Angle))));
            _pendulum.P = SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity;
            _pendulum.Pt = (float)(SinglePendulumSettings.Weight * SinglePendulumSettings.Gravity * Math.Sin(alpha));

            _alpha0_detail.Text = SinglePendulumSettings.Angle.ToString() + "°";
            _alpha_detail.Text = ((float)(MathHelper.ToDegrees((float)alpha))).ToString() + "°";
            _l_detail.Text = SinglePendulumSettings.RopeLengh.ToString() + "(m)";
            _g_detail.Text = SinglePendulumSettings.Gravity.ToString() + "(m/s²)";
            _m_detail.Text = SinglePendulumSettings.Weight.ToString() + "(kg)";
            _t_chuki_detail.Text = T.ToString() + "(s)";
            _a_detail.Text = A.ToString() + "(m)";
            _s_detail.Text = s.ToString() + "(m)";
            _vmax_detail.Text = V_max.ToString() + "(m/s)";
            _v_detail.Text = v.ToString() + "(m/s)";
            _time_detail.Text = _time.ToString() + "(s)";
            _p_detail.Text = _pendulum.P.ToString() + "(N)";
            _pt_detail.Text = _pendulum.Pt.ToString() + "(N)";
            _qmax_detail.Text = Q_max.ToString() + "(N)";
            _qmin_detail.Text = Q_min.ToString() + "(N)";
            _q_detail.Text = _pendulum.Q.ToString() + "(N)";
            _pn_detail.Text = _pendulum.Pn.ToString() + "(N)";
            _w_detail.Text = W.ToString() + "(J)";
            _wt_detail.Text = w_t.ToString() + "(J)";
            _wd_detail.Text = w_d.ToString() + "(J)";
        }

        bool _is_drag_pendulum = false;
        private void HandleInput()
        {
            while (TouchPanel.IsGestureAvailable)
            {

                GestureSample gestureSample = TouchPanel.ReadGesture();

                switch (gestureSample.GestureType)
                {
                    case GestureType.Tap:
                        if (_is_playing)
                        {
                            GetButton(ButtonTypes.Refresh).IsEnabled = true;
                            _is_playing = false;
                        }
                        else
                        {
                            GetButton(ButtonTypes.Refresh).IsEnabled = false;
                            _is_playing = true;
                        }
                        break;
                    case GestureType.FreeDrag:
                        if (!_is_playing)
                        {

                            if (gestureSample.Position.Y >= _pendulum.PendulumPositon.Y - _pendulum.PendulumTexture.Height
                        && gestureSample.Position.Y <= _pendulum.PendulumPositon.Y + _pendulum.PendulumTexture.Height
                        && gestureSample.Position.X >= _pendulum.PendulumPositon.X - _pendulum.PendulumTexture.Width
                        && gestureSample.Position.X <= _pendulum.PendulumPositon.X + _pendulum.PendulumTexture.Width)
                            {
                                _is_drag_pendulum = true;
                                Vector2 tmp_vect = gestureSample.Delta;
                                tmp_vect.Y = -tmp_vect.Y;

                                _rope.VectorForce += tmp_vect;
                                _rope.VectorForce = new Vector2(_rope.VectorForce.X, _rope.VectorForce.Y);


                                float b = _rope.VectorForce.X/ CM_PIXEL;
                                float c = _rope.VectorForce.Y/ CM_PIXEL;
                                if (b < 0)
                                    b = -b;
                                if (c < 0)
                                    c = -c;

                                SinglePendulumSettings.RopeLengh = (float)Math.Sqrt(b * b + c * c);
                                if (SinglePendulumSettings.RopeLengh > 9)
                                {
                                    SinglePendulumSettings.RopeLengh = 9;
                                }
                                else if (SinglePendulumSettings.RopeLengh < 1)
                                {
                                    SinglePendulumSettings.RopeLengh = 1;
                                }
                                SinglePendulumSettings.Angle = 90 - MathHelper.ToDegrees((float)Math.Acos(b / SinglePendulumSettings.RopeLengh));

                                if (_pendulum.PendulumPositon.X < SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2)
                                {
                                    SinglePendulumSettings.Fi = 180;
                                }
                                else if (_pendulum.PendulumPositon.X > SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2)
                                {
                                    SinglePendulumSettings.Fi = 0;
                                }
                                if (SinglePendulumSettings.Angle < 0.2)
                                {
                                    if (SinglePendulumSettings.Fi == 180)
                                    {
                                        SinglePendulumSettings.Fi = 0;
                                    }
                                    else
                                    {
                                        SinglePendulumSettings.Fi = 180;
                                    }
                                }
                                CalculateFist();
                            }
                        }
                        break;
                    case GestureType.DragComplete:
                        if (!_is_playing)
                        {
                            if (_is_drag_pendulum)
                            {
                                _time = 0;
                                _is_playing = true;
                                _is_drag_pendulum = false;
                                GetButton(ButtonTypes.Save).IsEnabled = true;
                            }
                        }
                        break;
                }
            }
        }
        /// <summary>
        /// Allows the page to draw itself.
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.White);
            elementRenderer.Render();
            spriteBatch.Begin();
            spriteBatch.Draw(_background, Vector2.Zero, Color.White);
            spriteBatch.Draw(elementRenderer.Texture, Vector2.Zero, Color.White);

            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);

            _rope.Draw(e);
            _pendulum.Draw(e);

            spriteBatch.End();
          
        }

        protected override void OnTap(GestureEventArgs e)
        {            
            base.OnTap(e);
        }

        private void SaveClick(object sender, System.EventArgs e)
        {
            if (!Guide.IsVisible)
            {
                _is_playing = false;
                // display the guide

                Guide.BeginShowKeyboardInput(PlayerIndex.One,
                    "Tên",       // title for the page
                    "Nhập tên mô phỏng",  // question for user
                    null,             // default text
                    new AsyncCallback(GotTextName),  // callback method 
                    this);                       // object reference
            }
        }
        void GotTextName(IAsyncResult result)
        {
            if (result.IsCompleted)
            {
                List<SinglePendulumData> datas = SinglePendulumData.Load();

                string text = Guide.EndShowKeyboardInput(result);

                if (text != null)
                {
                    if (text == "")
                    {
                        text = "unknown";
                    }
                    SinglePendulumSettings.save_active = false;
                    SinglePendulumData data = new SinglePendulumData(text, SinglePendulumSettings.Angle, SinglePendulumSettings.RopeLengh, SinglePendulumSettings.Gravity, SinglePendulumSettings.Weight, SinglePendulumSettings.Fi);
                    datas.Add(data);
                    SinglePendulumData.SaveData(datas);
                }
            }
        }

        public enum ButtonTypes
        {
            Save = 0,
            Refresh = 1
        }
        public ApplicationBarIconButton GetButton(ButtonTypes whichButton)
        {
            return ApplicationBar.Buttons[(int)whichButton]
               as ApplicationBarIconButton;
        }

        private void RefreshClick(object sender, System.EventArgs e)
        {
            CalculateFist();
            GetButton(ButtonTypes.Refresh).IsEnabled = false;

            ApplicationBar.Mode = ApplicationBarMode.Default;
            _is_playing = false;
        }

        private void InfoClick(object sender, System.EventArgs e)
        {
        	// TODO: Add event handler implementation here.
            NavigationService.Navigate(new Uri("/SinglePendulum/SinglePendulumInfoPage.xaml", UriKind.Relative));
        }

        private void LoadSimalatorClick(object sender, System.EventArgs e)
        {
        	// TODO: Add event handler implementation here.
            _is_playing = false;
            NavigationService.Navigate(new Uri("/SinglePendulum/SaveSinglePendulumPage.xaml", UriKind.Relative));
        }

        private void ThongSo_Click(object sender, System.EventArgs e)
        {
            _is_playing = false;
            NavigationService.Navigate(new Uri("/SinglePendulum/EditSinglePendulumPage.xaml", UriKind.Relative));
        }
    }
}